package cn.remex.core.util.lock;

import cn.remex.core.exception.ServiceCode;
import cn.remex.core.util.Assert;
import cn.remex.core.util.Judgment;
import cn.remex.core.util.MapHelper;
import cn.remex.db.Database;
import cn.remex.db.DbRvo;
import cn.remex.db.model.SysStatus;
import cn.remex.db.rsql.RsqlConstants;
import cn.remex.db.sql.WhereRuleOper;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.UUID;

/**
 * Created by guoqi on 2016/6/30.
 */
public class Lock {

    private final static int timeOut = 60; // 分钟
    public static boolean getLock(String lockName){
        UUID uuid = UUID.randomUUID();
        LocalDateTime localDateTime = LocalDateTime.now();
        String lockNames = "LOCK"+lockName;
        SysStatus sysStatus = Database.getSession().createDbCvo(SysStatus.class)
                .filterBy(SysStatus::getKey, WhereRuleOper.equal,lockNames)
                .ready().queryBean();

        if (Judgment.nullOrBlank(sysStatus)){ // 没有key，则新建立
            sysStatus = new SysStatus();
            sysStatus.setKey(lockNames);
            sysStatus.setNote(uuid.toString()); //标志位 抢锁资源
            sysStatus.setDesc(localDateTime.toString());
            sysStatus.setStatus(RsqlConstants.SysStatusEnum.LOCKED);
            try {
                Database.getSession().store(sysStatus);
                return true;
            }catch (Exception e){
                return false;
            }
        }else { // 有锁情况
            String oldUID =sysStatus.getNote();
            LocalDateTime oldTime = LocalDateTime.parse(sysStatus.getDesc());
            if(sysStatus.getStatus().equals(RsqlConstants.SysStatusEnum.LOCKED)&&oldTime.until(localDateTime, ChronoUnit.MINUTES)>timeOut){ //当超过60分钟超时
                sysStatus.setNote(uuid.toString());
                sysStatus.setDesc(localDateTime.toString());
                sysStatus.setStatus(RsqlConstants.SysStatusEnum.LOCKED);
                try {
                    Database.getSession().store(sysStatus);
                    return true;
                }catch (Exception e){
                    return false;
                }
            }else if (sysStatus.getStatus().equals(RsqlConstants.SysStatusEnum.UNLOCKED)){
                try {
                    Map<String,Object> map = MapHelper.toMap("note",uuid.toString(),"desc",localDateTime.toString(),"oldnote",oldUID,"id",sysStatus.getId(),"key",lockNames);
                    DbRvo dbRvo = Database.getSession().executeUpdate("UPDATE SysStatus SET note = :note,`desc`= :desc,status='LOCKED' WHERE note = :oldnote AND id= :id AND status='UNLOCKED' AND  `key` = :key", map);
                    return dbRvo.getEffectRowCount() == 1;
                }catch (Exception e){
                    return false;
                }
            }else {
                return false;
            }
        }
    }

    public static void unlock(String lockName){
        String lockNames = "LOCK"+lockName;
        SysStatus sysStatus = Database.getSession().createDbCvo(SysStatus.class)
                .filterBy(SysStatus::getKey, WhereRuleOper.equal,lockNames)
                .ready().queryBean();
        Assert.notNull(sysStatus, ServiceCode.FAIL,"没有获取到锁，无法关闭！ 锁名为："+lockName);
        sysStatus.setStatus(RsqlConstants.SysStatusEnum.UNLOCKED);
        Database.getSession().store(sysStatus);
    }
}
